package com.wd.cloud.applet.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author hjx
 * @date 2020-03-24
 */
public class SignUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(SignUtil.class);
    /**
     * @param params 所有的请求参数都会在这里进行排序加密
     * @return 验证签名结果
     */
    public static boolean verifySign(JSONObject params, String appSecret) {
        System.out.println(params);
        String urlSign = params.get("sign").toString();
        if (org.springframework.util.StringUtils.isEmpty(urlSign)) {
            return false;
        }
        // 加密参数，得到sing
        String paramsSign = getSign(params, appSecret);
        return !org.springframework.util.StringUtils.isEmpty(paramsSign) && urlSign.equals(paramsSign);
    }
    /**
     * @param params 所有的请求参数都会在这里进行排序加密
     * @return 得到签名
     */
    private static String getParamsSign(JSONObject params, String appSecret) {
        params.remove("sign");
        //params.remove("shopImagesList");
        StringBuilder waitingMd5Params = new StringBuilder();
        SortedMap<String, Object> treeMap = sortMapByKey(params);
        for (Map.Entry entry : treeMap.entrySet()) {
            waitingMd5Params.append(entry.getKey()).append(entry.getValue());
        }
        String paramsStr = waitingMd5Params.toString();
        LOGGER.info("doSignAround==>待签名字符串==>" + params);
        String result = appSecret + paramsStr + appSecret;
        LOGGER.info("doSignAround==>签名结果==>" + params);
        return Md5Utils.hash(result);
    }
    /**
     * 获取签名
     *
     * @param params
     * @return
     */
    public static boolean checkSign(JSONObject params) {
        try {
            String sign = null;
            if (params.containsKey("sign")) {
                sign = params.getString("sign");
                params.remove("sign");
            }
            Map<String, Object> map = sortKey(params);
            StringBuffer sb = new StringBuffer();
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                Object value = map.get(key);
                if (value == null) {
                    value = "";
                } else if (value instanceof Map || value instanceof List) {
                    char[] chs = JSON.toJSONString(value, SerializerFeature.WriteMapNullValue).toCharArray();
                    Arrays.sort(chs);
                    value = new String(chs);
                }
                sb.append(key + value);
            }
            String signStr = sb.append(AesUtil.key).toString();
            LOGGER.info("API接口待签名字符串：" + signStr);
            String tsign = Md5Utils.hash(signStr);
            LOGGER.info("API接口签名字符串：" + tsign);
            return (!StringUtils.isEmpty(sign) && sign.equalsIgnoreCase(tsign));
        } catch (Exception e) {
            return false;
        }
    }
    public static String getSign(JSONObject params, String secretKey, String timeSpan) {
        params.remove("sign");
        StringBuilder strParams = new StringBuilder();
        Map<String, Object> map = sortKey(params);
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Object value = map.get(key);
            if (!HelperUtils.isNullEmpty(value)) {
                strParams.append(key + value);
            }
        }
        strParams.append(secretKey);
        if (!HelperUtils.isNullOrTrimEmpty(timeSpan)) {
            strParams.append(timeSpan);
        }
        LOGGER.info("待签名数据==>" + strParams.toString());
        String strParamsMd5 = Md5Utils.hash(strParams.toString());
        LOGGER.info("签名结果==>" + strParamsMd5);
        return strParamsMd5;
    }
    /**
     * JSON转顺序排序的Map
     *
     * @param json 原始json
     * @return 响应的map
     */
    private static SortedMap<String, Object> sortMapByKey(JSONObject json) {
        SortedMap<String, Object> treeMap = new TreeMap<>();
        Iterator<String> keys = json.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
            Object value = json.get(key);
            //判断传入kay-value中是否含有""或null
            if (json.get(key) == null || value == null || value.toString().length() == 0) {
                //当JSON字符串存在null时,不将该kay-value放入Map中,即显示的结果不包括该kay-value
                continue;
            }
            // 判断是否为JSONArray(json数组)
            if (value instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) value;
                List<Object> arrayList = new ArrayList<>();
                for (Object object : jsonArray) {
                    // 判断是否为JSONObject，如果是 转化成TreeMap
                    if (object instanceof JSONObject) {
                        object = sortMapByKey(JSONObject.parseObject(object.toString()));
                    }
                    arrayList.add(object);
                }
                treeMap.put(key, arrayList);
            } else {
                //判断该JSON中是否嵌套JSON
                boolean flag = isJsonValid(value.toString());
                if (flag) {
                    //若嵌套json了,通过递归再对嵌套的json(即子json)进行排序
                    value = sortMapByKey(JSONObject.parseObject(value.toString()));
                }
                // 其他基础类型直接放入treeMap
                // JSONObject可进行再次解析转换
                treeMap.put(key, value);
            }
        }
        return treeMap;
    }
    /**
     * 校验是否是JSON字符串
     *
     * @param json 传入数据
     * @return 是JSON返回true, 否则false
     */
    private static boolean isJsonValid(String json) {
        try {
            JSONObject.parseObject(json);
        } catch (JSONException ex) {
            return false;
        }
        return true;
    }
    public static String getSign(JSONObject params, String secretKey) {
        return getSign(params, secretKey, "");
    }
    /**
     * 对参数key进行排序
     *
     * @param params
     * @return
     */
    private static Map<String, Object> sortKey(JSONObject params) {
        Map<String, Object> sortMap = new TreeMap<>(new MapKeyComparator());
        sortMap.putAll(params);
        return sortMap;
    }
    private static class MapKeyComparator implements Comparator<String> {
        @Override
        public int compare(String str1, String str2) {
            return str1.compareTo(str2);
        }
    }
}
